﻿using CSRedis;
using DotNetCommon;
using Flurl.Http;
using furion.blog.Application.Contracts;
using furion.blog.Domain.Mongo;
using furion.blog.Domain.Shared.Dto.Wx;
using furion.blog.Domain.Shared.Dto.Wx.MiniProgram;
using furion.blog.Domain.Shared.Enum;
using furion.blog.Utils;
using Furion;
using Furion.DependencyInjection;
using Masuit.Tools.DateTimeExt;
using MongoDB.Entities;
using NewLife.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace furion.blog.Application
{
    /// <summary>
    /// 微信服务
    /// </summary>
    public class WxService : IWxService, ISingleton
    {
        string APPID = null;
        string SECRET = null;


        private readonly CSRedisClient[] _csredis;
        public WxService(CSRedisClient[] csredis)
        {
            APPID = App.Configuration["MiniProgram:AppId"];
            SECRET = App.Configuration["MiniProgram:Secret"];
            this._csredis = csredis;
        }

        /// <summary>
        /// 通过code获取会员的openid等信息(小程序)
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public async Task<Code2SessionDto> Code2Session(string code)
        {
            var ret = await WxRequest(new WxRequestDto
            {
                Url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + APPID + "&secret=" + SECRET + "&js_code=" + code + "&grant_type=authorization_code",
                RequestMethod = "GET",
                ApiName = WxRequestApiEnum.MiniProgramCode2Session.ToString(),
            });
            var json = JsonConvert.DeserializeObject<Code2SessionDto>(ret);
            return json;
        }

        /// <summary>
        /// 小程序发送信息给会员
        /// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/customer-message/customerServiceMessage.send.html
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<bool> SendMsgToMember(SendMsgToMemberDto dto)
        {
            Console.WriteLine("通过微信发送信息给客户====>");
            bool ret = false;
            var accessToken = GetMiniProgramAccessToken();
            if (!string.IsNullOrWhiteSpace(accessToken))
            {
                dto.AccessToken = accessToken;
                switch (dto.MsgType.ToLower())
                {
                    case "text": { ret = await SendTextMsgToMember(dto); }; break;
                    default: { /*默认不做任何操作*/ }; break;
                }
            }
            return ret;
        }

        #region 私有方法

        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        private async Task<string> WxRequest(WxRequestDto dto)
        {
            string ret = null;
            Stopwatch watch = new Stopwatch();
            watch.Start();
            if (dto.RequestMethod.ToUpper() == "GET")
            {
                ret = await dto.Url.GetStringAsync();
            }
            else if (dto.RequestMethod.ToUpper() == "POST")
            {
                ret = await dto.Url.PostJsonAsync(dto.PostData).ReceiveString();
            }
            watch.Stop();
            long usedTime = watch.ElapsedMilliseconds;
            watch = null;

            try
            {
                await DB.SaveAsync(new WxRequestLog
                {
                    ID = IdUtil.Id().ToString(),
                    Url = dto.Url,
                    PostData = JsonConvert.SerializeObject(dto.PostData),
                    Result = ret,
                    ApiName = dto.ApiName,
                    UsedTime = usedTime,
                    RequestMethod = dto.RequestMethod,
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return ret;
        }

        /// <summary>
        /// 获取AccessToken
        /// </summary>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.Synchronized)]//标识：同一时间只能同一线程进行访问该方法
        private string GetMiniProgramAccessToken()
        {
            var accessToken = this._csredis[12].Get<string>("miniprogram_access_token");
            int tryTimes = 1;
            if (string.IsNullOrEmpty(accessToken))
            {
                while (tryTimes <= 5)
                {
                    var url = string.Format(@"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", App.Configuration["MiniProgram:AppId"], App.Configuration["MiniProgram:Secret"]);
                    /*var ret = url.GetStringAsync().Result;
                    Console.WriteLine("获取access_token====>");
                    Console.WriteLine(ret);*/
                    var ret = WxRequest(new WxRequestDto {
                        Url = url,
                        RequestMethod = "GET",
                        ApiName = WxRequestApiEnum.MiniProgramAccessToken.ToString(),
                    }).Result;
                    JObject json = JObject.Parse(ret);
                    if (json.ContainsKey("access_token")) {
                        //请求成功
                        accessToken = json.Value<string>("access_token");
                        int expiresIn = json.Value<int>("expires_in");
                        var done = this._csredis[12].Set("miniprogram_access_token",accessToken,(expiresIn-100));
                        if (done) {
                            tryTimes = 10;//跳出循环
                        }
                    }
                }
            }
            return accessToken;
        }

        /// <summary>
        /// 发送纯文字信息给客户
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        private async Task<bool> SendTextMsgToMember(SendMsgToMemberDto dto) {
            var data = new { 
                access_token = dto.AccessToken, 
                touser = dto.ToUser,
                msgtype = "text", 
                text=dto.Text,
            };
            string url = string.Format(@"https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}",dto.AccessToken);
            /*var ret = (await url.PostJsonAsync(data)).GetStringAsync();
            Console.WriteLine(ret);
            return true;*/
            var ret = await WxRequest(new WxRequestDto {
                Url = url,
                RequestMethod = "POST",
                PostData = data,
                ApiName = WxRequestApiEnum.MiniProgramSendMessageToCustomer.ToString(),
            });
            return true;
        }

        #endregion
    }
}
